<template>
  <div ref="container"></div>
</template>

<script>
import {ref, onMounted, nextTick} from 'vue';
import { PivotSheet, S2Event, DataCell, RowCell,ColCell, CustomText, renderText, getEmptyPlaceholder} from '@antv/s2';

export default {
  setup() {
    const container = ref(null);
    let s2;


    onMounted(() => {
      // 工具函数：文本分行逻辑
      const splitTextIntoLines = (text, maxWidth, charWidth) => {
        const lines = [];
        let currentLine = '';

        [...text].forEach((char) => {
          const tempLine = currentLine + char;
          if (tempLine.length * charWidth > maxWidth) {
            lines.push(currentLine);
            currentLine = char;
          } else {
            currentLine = tempLine;
          }
        });
        if (currentLine) lines.push(currentLine);
        return lines;
      };

      // 工具函数：计算动态行高
      const calculateHeaderRowHeight = (viewMeta) => {
        const fontSize = 12, padding = 8, lineHeight = 14;
        const lines = splitTextIntoLines(viewMeta.value || '', viewMeta.width - 2 * padding, fontSize);
        return lines.length * lineHeight + padding * 2;
      };

      const calculateHeaderColWidth = (viewMeta) => {
        return headerColWidths[viewMeta.field];
      }

      class CustomColCell extends ColCell {
        drawTextShape() {
          let { x, y, width, height, value } = this.getMeta();
          const text = String(value || ''); // 获取单元格文本内容

          const textStyle = {
            fontSize: 12,
            fill: '#000',
            textAlign: 'left',
            textBaseline: 'middle', // 垂直基线
          };

          const fontSize = 12; // 字体大小
          const padding = 8; // 内边距
          const lineHeight = 12; // 行高
          const availableWidth = width - 2 * padding; // 可用绘制宽度
          // 分行逻辑：根据宽度动态分割文本
          const lines = splitTextIntoLines(text, availableWidth, fontSize);

          // 计算文本总高度并居中
          const totalTextHeight = lines.length * lineHeight;
          const startY = y + (height - totalTextHeight) / 2 + (lineHeight/2); // 起始 Y 坐标;

          // 绘制每行文本
          lines.forEach((line, lineIndex) => {
            let lineY = 0;
            if(lineIndex == 0){
              lineY = startY + lineIndex * lineHeight; // 当前行的 Y 坐标
            }else{
              lineY = startY + lineIndex * lineHeight + 2; // 当前行的 Y 坐标
            }
            const totalChars = line.length; // 当前行字符数

            // 计算字符间距（分散对齐）
            const spaceBetween = totalChars > 1
                ? (availableWidth - textStyle.fontSize * totalChars) / (totalChars - 1)
                : 0;

            // 起始 X 坐标
            let startX = x + padding;

            // 绘制每个字符
            [...line].forEach((char, charIndex) => {
              const charX = startX + charIndex * (textStyle.fontSize + spaceBetween); // 当前字符 X 坐标
              const textShape = renderText({
                group: this,
                textShape: [this.textShape],
                style: {
                  ...textStyle,
                  x: charX,
                  y: lineY,
                  text: char,
                },
              });
              this.addTextShape(textShape);
            });
          });
        }
      }

      class CustomRowCell extends RowCell {
        /**
         * 根据下标计算数组中 >= index 的元素之和
         * @param {number[]} arr 数组
         * @param {number} index 下标
         * @returns {number} 元素之和
         */
        calculateSumFromIndex(arr, index) {
          if (index < 0 || index >= arr.length) {
            throw new Error("Index is out of bounds");
          }

          // 使用 slice 提取子数组并计算和
          return arr.slice(index).reduce((sum, num) => sum + num, 0);
        }

        calculateCellWidth(node, widths, level, maxLevel){
          // 当前层级的默认宽度
          const currentWidth = widths[level] || 0;

          // 如果是叶子节点（没有 children 或到达最大层级），使用当前层级宽度
          if (level === maxLevel || !node.isLeaf) {
            return currentWidth;
          }else{
            return this.calculateSumFromIndex(widths, level);
          }
        }

        calculateCellHeight(node) {
          if (node.isLeaf) {
            // 如果是叶子节点，直接返回其高度
            return node.height || 0; // 默认高度为 0（防止未定义）
          } else {
            // 如果有子节点，递归计算子节点的高度总和
            const totalHeight = node.children.reduce((sum, child) => {
              return sum + this.calculateCellHeight(child);
            }, 0);
            return totalHeight+4;  //  这块补4是显示上有偏移4
          }
        }

        drawTextShape() {
          const { x, y, value, isLeaf, level} = this.meta;
          //自身计算表旁宽度有问题，自定义实现
          const width = this.calculateCellWidth(this.meta, sideColWidths, level, this.meta.hierarchy.maxLevel);
          const height = this.calculateCellHeight(this.meta);
          const padding = 10; // 内边距
          const textStyle = { fontSize: 12, fill: '#000', textBaseline: 'middle' };
          const lineHeight = textStyle.fontSize + 2; // 行高

          if (!isLeaf) {
            // 非叶子节点：竖排分散对齐、自动换列、列内容水平居中
            const chars = String(value || '').split(''); // 将值拆分为字符数组
            const availableHeight = height - 2 * padding; // 可用高度
            const maxCharsPerColumn = Math.floor(availableHeight / lineHeight); // 每列最大字符数
            const totalColumns = Math.ceil(chars.length / maxCharsPerColumn); // 总列数
            const columnWidth = textStyle.fontSize + 2; // 每列宽度
            const totalContentWidth = totalColumns * columnWidth; // 内容总宽度
            const startX = x + (width - totalContentWidth) / 2; // 起始点水平居中

            // 遍历每列
            for (let col = 0; col < totalColumns; col++) {
              const colStartIndex = col * maxCharsPerColumn;
              const colChars = chars.slice(colStartIndex, colStartIndex + maxCharsPerColumn); // 当前列的字符
              const charSpacing = colChars.length > 1
                  ? (availableHeight - colChars.length * textStyle.fontSize) / (colChars.length - 1) // 分散对齐间距
                  : 0;

              colChars.forEach((char, rowIndex) => {
                const charX = startX + col * columnWidth + columnWidth / 2; // 当前列的 X 坐标（水平居中）
                const charY = y + padding + rowIndex * (textStyle.fontSize + charSpacing); // 当前字符的 Y 坐标
                renderText({
                  group: this,
                  style: {
                    ...textStyle,
                    x: charX,
                    y: charY,
                    text: char,
                    textAlign: 'center',
                  },
                });
              });
            }
          } else {
            console.log("文本：",value , "宽度: ", width);
            // 叶子节点：横排分散对齐并支持换行
            const availableWidth = width - 2 * padding; // 可用宽度
            const lines = splitTextIntoLines(value || '', availableWidth, textStyle.fontSize); // 自动换行

            const startY = y + (height - lines.length * lineHeight) / 2 + lineHeight / 2; // 垂直居中
            lines.forEach((line, lineIndex) => {
              const totalChars = line.length;
              const spaceBetween = totalChars > 1
                  ? (availableWidth - totalChars * textStyle.fontSize) / (totalChars - 1) // 分散对齐计算
                  : 0;
              let startX = x + padding + 12 / 2; // 起始点
              [...line].forEach((char, charIndex) => {
                const charX = startX + charIndex * (textStyle.fontSize + spaceBetween); // 每个字符的 X 坐标
                renderText({
                  group: this,
                  style: {
                    ...textStyle,
                    x: charX,
                    y: startY + lineIndex * lineHeight,
                    text: char,
                    textAlign: 'center',
                  },
                });
              });
            });
          }
        }
      }

      class CustomDataCell extends DataCell {
        getFieldValue(){
          // 获取行 ID 和列 ID
          const { x, y, rowId, colId } = this.getMeta();
          // 分割 `rowId` 和 `colId` 获取具体字段
          const rowFields = rowId.split('[&]').slice(1); // 跳过 'root'
          const colFields = colId.split('[&]').slice(1); // 跳过 'root'

          // 遍历 `displayData` 查找匹配的记录
          const data = this.spreadsheet.dataSet.displayData;
          const valuesField = this.spreadsheet.dataSet.fields.values[0]; // 获取 'value' 字段

          let value = null;
          for (const item of data) {
            // 判断 `rowFields` 和 `colFields` 是否都匹配
            const isRowMatch = rowFields.every(field => item[field] !== undefined);
            const isColMatch = colFields.every(field => item[field] !== undefined);

            if (isRowMatch && isColMatch) {
              value = item[valuesField]; // 获取数据值
              break;
            }
          }

          return value;
        }
      }

      const customTree = [
        {
          field: 'a-1',
          title: '财政教育经费投入收到捡垃圾几点几分解决法鸡打两局基督教啊了解倒垃圾阿斯顿发束带结发垃圾袋反垃圾飞拉达较大发啦代发发的三到付件拉法基到啦的',
          width: 120,
          height: 60,
          wordTR: 'vl',
          children: [
            {
              field: 'a-1-1',
              title: '项目经费',
              width: 60,
              children: [
                {
                  field: 'bzhjs',
                  width: 30,
                  title: '标准化建设',
                  children: [],
                },
                {
                  field: 'xxhjs',
                  width: 30,
                  title: '信息化建设',
                  children: [],
                },
              ],
            },
            {
              field: 'a-1-2',
              title: '基础拨款',
              width: 30,
              children: [],
            },
          ],
        },
        {
          field: 'a-2',
          title: '其他投入',
          children: [],
        },
      ];

      // 定义省市县的自定义树形结构
      const rowsTreeHierarchy = [
        {
          field: 'hz',
          title: '汇总',
          wordTR: 'vl',
          width: 180,
          height: 30,
          level: 1,
          description: '汇总',
        },
        {
          field: 'beijing',
          title: '北京市',
          wordTR: 'vl',
          width: 30,
          height: 30,
          level: 1,
          description: '北京省描述',
          children: [
            {
              field: 'fz',
              title: '分计sdfsfdjsaldj',
              wordTR: 'vl',
              width: 40,
              level: 2,
              height: 30,
              description: '分计',
              children: [],
            },
            {
              field: 'haidian',
              title: '海淀区秒的的按到',
              wordTR: 'vl',
              width: 80,
              height: 30,
              level: 2,
              description: '海淀区描述',
              children: [
                {
                  field: 'zizhuyuan',
                  title: '紫竹院',
                  width: 120,
                  height: 30,
                  level: 3,
                  description: '紫竹院描述',
                  children: [],
                },
                {
                  field: 'zhongguancun',
                  title: '中关村',
                  width: 120,
                  height: 60,
                  level: 3,
                  description: '中关村描述',
                  children: [],
                },
              ],
            }
          ],
        },
        {
          field: 'shanghai',
          title: '上海市',
          width: 30,
          height: 30,
          level: 1,
          description: '上海省描述',
          children: [
            {
              field: 'huangpu',
              title: '黄浦区军校区域手动阀代发费撒打发',
              level: 2,
              height: 60,
              description: '黄浦区描述',
              children: [],
            }
          ],
        }
      ];

      const data = [
        {
          'beijing': '北京市',
          'haidian': '海淀区',
          'zizhuyuan': '紫竹院',
          'a-1': '财政教育经费投入',
          'a-1-1': '项目经费',
          'bzhjs': '标准化建设',
          'value': 12121
        },{
          'beijing': '北京市',
          'haidian': '海淀区',
          'zizhuyuan': '紫竹院',
          'a-1': '财政教育经费投入',
          'a-1-1': '项目经费',
          'xxhjs': '信息化建设',
          'value': 322
        },{
          'beijing': '北京市',
          'haidian': '海淀区',
          'zizhuyuan': '紫竹院',
          'a-1': '财政教育经费投入',
          'a-1-2': '基础拨款',
          'value': 555
        }
        ,{
          'shanghai': '上海市',
          'huangpu': '黄浦区',
          'a-1': '财政教育经费投入',
          'a-1-2': '基础拨款',
          'value': 2127
        }
      ];

      // 获取树形数据的最大层级
      const getMaxLevel = (tree) => {
        let maxLevel = 0;

        function traverse(node) {
          if (node.level > maxLevel) maxLevel = node.level;
          if (node.children && node.children.length > 0) {
            node.children.forEach(traverse);
          }
        }

        tree.forEach(traverse);
        return maxLevel;
      }

      /**
       * 计算表旁每列宽度
       * @param {Array} tree - 树形结构
       * @returns {Array} - 每列宽度
       */
      const calculateSideColumnWidths = (tree) => {
        const maxLevel = getMaxLevel(tree);
        const columnWidths = Array(maxLevel).fill(0); // 每列初始宽度为 0

        function traverse(node) {
          const { level, width, children } = node;

          if (level <= maxLevel) {
            // 计算非叶子节点宽度
            if (children && children.length > 0) {
              columnWidths[level - 1] = Math.max(columnWidths[level - 1], width || 0);
              children.forEach(traverse); // 递归处理子节点
            } else if (level === maxLevel) {
              // 如果是最大层级，直接计算宽度
              columnWidths[level - 1] = Math.max(columnWidths[level - 1], width || 0);
            }
          }
        }

        tree.forEach(traverse);
        return columnWidths;
      }


      const calculateSideRowHeights = (tree, result) =>{
        tree.forEach(node => {
          // 如果是叶子节点，记录其行高到对应的层级
          if (!node.children || node.children.length === 0) {
            result[node.field] = node.height;
          } else {
            // 如果是父节点，递归处理其子节点
            calculateSideRowHeights(node.children, result);
          }
        });
        return result;
      }

      const calculateHeaderColWidths = (tree, result) =>{
        tree.forEach(node => {
          // 如果是叶子节点，记录其行高到对应的层级
          if (!node.children || node.children.length === 0) {
            result[node.field] = node.width;
          } else {
            // 如果是父节点，递归处理其子节点
            calculateHeaderColWidths(node.children, result);
          }
        });
        return result;
      }

      const sideColWidths = calculateSideColumnWidths(rowsTreeHierarchy);
      const sideRowHeights = calculateSideRowHeights(rowsTreeHierarchy, {});
      const headerColWidths = calculateHeaderColWidths(customTree, {});

      // 递归计算每列宽度
      const calculateSideColWidth = (nodeField) => {
        return sideColWidths[nodeField.level]
      }

      /**
       * 计算节点高度
       * @param {Object} node 当前节点
       * @param {number} rowHeight 行高
       * @returns {number} 节点高度
       */
      const calculateSideRowHeight =   (nodeField) => {
         return sideRowHeights[nodeField.field];
      }

      const s2DataConfig = {
        fields: {
          rows: rowsTreeHierarchy,
          columns: customTree,
          values: ['value'],
        },
        data,
      };

      const s2Options = {
        width: 800,
        height: 1200,
        colCell: (node, spreadsheet, headerConfig) => {
          return new CustomColCell(node, spreadsheet, headerConfig);
        },
        dataCell: (viewMeta, spreadsheet) => {
          return new CustomDataCell(viewMeta, spreadsheet);
        },
        rowCell: (node, spreadsheet, headerConfig) => {
          return new CustomRowCell(node, spreadsheet, headerConfig);
        },
        hierarchyType: 'grid',
        style: {
          rowCell: {
            // 固定配置: 行头单元格 100px
            width: calculateSideColWidth,
            // 动态配置: 叶子节点 300px, 非叶子节点 200px
            height: calculateSideRowHeight,
          },
          colCell:{
            width: calculateHeaderColWidth,
            height: calculateHeaderRowHeight, // 动态设置高度
          },
          colCfg: {
            width: 100,
          },
        },
      };

      // 初始化 S2 实例
      s2 = new PivotSheet(container.value, s2DataConfig, s2Options);
      s2.render();

    });

    return {
      container,
    };
  },
};
</script>

<style scoped>
.container {
  margin: 20px;
}
</style>